/*
 * Copyright 2012-2020 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.boot.autoconfigure;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.context.TypeExcludeFilter;
import org.springframework.context.annotation.AnnotationBeanNameGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.core.annotation.AliasFor;
import org.springframework.data.repository.Repository;

/**
 * 表示一个 {@link Configuration 配置} 类，它声明一个或多个 {@link Bean @Bean} 方法，
 * 并触发 {@link EnableAutoConfiguration 自动配置} 和 {@link ComponentScan 组件扫描}。
 * 这是一个方便的组合注解，等效于同时声明 {@code @Configuration}、
 * {@code @EnableAutoConfiguration} 和 {@code @ComponentScan}。
 *
 * @author Phillip Webb
 * @author Stephane Nicoll
 * @author Andy Wilkinson
 * @since 1.2.0
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration  // 开启自动装配
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {

	/**
	 * 排除指定的自动配置类，使其永远不会被应用。
	 * @return 要排除的类
	 */
	@AliasFor(annotation = EnableAutoConfiguration.class)
	Class<?>[] exclude() default {};

	/**
	 * 排除指定的自动配置类名，使其永远不会被应用。
	 * @return 要排除的类名
	 * @since 1.3.0
	 */
	@AliasFor(annotation = EnableAutoConfiguration.class)
	String[] excludeName() default {};

	/**
	 * 要扫描的基础包，用于查找带注解的组件。
	 * 使用 {@link #scanBasePackageClasses} 可替代字符串形式的包名，提供类型安全的方式。
	 * <p>
	 * <strong>注意：</strong>此设置仅作为 {@link ComponentScan @ComponentScan} 的别名。
	 * 它对 {@code @Entity} 扫描或 Spring Data {@link Repository} 扫描无效。
	 * 若需要扫描实体或仓库，应该额外添加
	 * {@link org.springframework.boot.autoconfigure.domain.EntityScan @EntityScan} 和
	 * {@code @Enable...Repositories} 注解。
	 * @return 要扫描的基础包
	 * @since 1.3.0
	 */
	@AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
	String[] scanBasePackages() default {};

	/**
	 * 类型安全的方式，用于指定要扫描的带注解组件的包，作为 {@link #scanBasePackages} 的替代方案。
	 * 每个指定类所在的包将被扫描。
	 * <p>
	 * 建议在每个包中创建一个特殊的无操作标记类或接口，仅用于被该属性引用。
	 * <p>
	 * <strong>注意：</strong>此设置仅作为 {@link ComponentScan @ComponentScan} 的别名。
	 * 它对 {@code @Entity} 扫描或 Spring Data {@link Repository} 扫描无效。
	 * 若需支持这些功能，应添加
	 * {@link org.springframework.boot.autoconfigure.domain.EntityScan @EntityScan}
	 * 和 {@code @Enable...Repositories} 注解。
	 * @return 要扫描的基础包
	 * @since 1.3.0
	 */
	@AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
	Class<?>[] scanBasePackageClasses() default {};

	/**
	 * 用于在 Spring 容器中为检测到的组件命名的 {@link BeanNameGenerator} 类。
	 * <p>
	 * 默认值为 {@link BeanNameGenerator} 接口本身，表示处理此 {@code @SpringBootApplication}
	 * 注解的扫描器将使用其继承的 Bean 名称生成器，例如默认的
	 * {@link AnnotationBeanNameGenerator}，或在应用上下文启动时提供的任何自定义实例。
	 * @return 要使用的 {@link BeanNameGenerator}
	 * @see SpringApplication#setBeanNameGenerator(BeanNameGenerator)
	 * @since 2.3.0
	 */
	@AliasFor(annotation = ComponentScan.class, attribute = "nameGenerator")
	Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;

	/**
	 * 指定是否对 {@link Bean @Bean} 方法进行代理，以强制执行 Bean 的生命周期行为，
	 * 例如即使在用户代码中直接调用 {@code @Bean} 方法，也能返回共享的单例 Bean 实例。
	 * 此特性依赖于方法拦截，通常通过运行时生成的 CGLIB 子类实现，
	 * 这会带来一些限制，例如配置类及其方法不能声明为 {@code final}。
	 * <p>
	 * 默认值为 {@code true}，允许在配置类内部进行“Bean 之间的引用”，
	 * 以及外部调用该配置类中的 {@code @Bean} 方法（例如从另一个配置类中）。
	 * 如果不需要此功能（即每个 {@code @Bean} 方法都是自包含的、为容器提供简单工厂方法），
	 * 可将该标志设置为 {@code false}，以避免 CGLIB 子类处理。
	 * <p>
	 * 关闭 Bean 方法拦截后，{@code @Bean} 方法将被单独处理，行为类似于声明在非
	 * {@code @Configuration} 类中的情况，即“@Bean 精简模式”
	 *（参见 {@link Bean @Bean} 的 Javadoc）。
	 * 因此其行为等同于移除 {@code @Configuration} 标注。
	 * @since 2.2
	 * @return 是否代理 {@code @Bean} 方法
	 */
	@AliasFor(annotation = Configuration.class)
	boolean proxyBeanMethods() default true;

}
